using System;
using System.ComponentModel;
using System.Globalization;


namespace SharpGL.Media3D
{
    /// <summary>
    ///	This namespace contains classes for use with the .NET design surface,
	///	typeconverters, UI editors etc. Most clients can safely ingore this, 
	///	it's not important 3D code, it just makes editing it easier.
    ///	</summary>
	namespace NETDesignSurface
	{
        /// <summary>
        ///	Converters are used to change objects of one type into another, at design time
		///	and also programmatically.
        ///	</summary>
		namespace Converters
		{
			/// <summary>
            /// The Point3DConverter class allows you to edit points in the properties window.
			/// </summary>
			internal class Point3DConverter : ExpandableObjectConverter 
			{
                private const char coordinatesSeparator = ';';

				public override bool CanConvertFrom(ITypeDescriptorContext context, Type t) 
				{
					//	We allow conversion from a string.
					if (t == typeof(string)) 
						return true;
			
					return base.CanConvertFrom(context, t);
				}

				public override object ConvertFrom(ITypeDescriptorContext context, 
					CultureInfo culture, object value) 
				{
					//	If it's a string, we'll parse it for coords.
					if (value is string) 
					{
						try 
						{
							string s = (string) value;
										
							//	Parse the format (x, y, z).
							int openbracket = s.IndexOf('(');
                            int firstseparator = s.IndexOf(coordinatesSeparator);
                            int secondseparator = s.IndexOf(coordinatesSeparator, firstseparator + 1);
							int closebracket = s.IndexOf(')');
					
							float xValue, yValue, zValue;

							if(firstseparator != -1 && openbracket != -1) 
							{
								//	We have the separator and open bracket, so get x.
								string parsed = s.Substring(openbracket + 1, (firstseparator - (openbracket + 1)));
								parsed.Trim();
                                xValue = float.Parse(parsed, culture);
						
								if(firstseparator != -1 && secondseparator != -1)
								{
									parsed = s.Substring(firstseparator + 1, (secondseparator - (firstseparator + 1)));
									parsed.Trim();
                                    yValue = float.Parse(parsed, culture);
						
									if(secondseparator != -1 && closebracket != -1)
									{
										parsed = s.Substring(secondseparator + 1, (closebracket - (secondseparator + 1)));
										parsed.Trim();
                                        zValue = float.Parse(parsed, culture);
								
										return new Point3D(xValue, yValue, zValue);
									}
								}
							}
						}
						catch
                        {
                        }
						//	Somehow we couldn't parse it.
						throw new ArgumentException("Can not convert '" + (string)value + 
							                        "' to type Point3D.");
					}

					return base.ConvertFrom(context, culture, value);
				}
                                 
				public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, 
					object value, Type destType) 
				{
					if (destType == typeof(string) && value is Point3D) 
					{
						//	We can easily convert a point to a string, format (x, y, z).
						Point3D v = (Point3D)value;

                        return "(" + v.X.ToString(culture) + coordinatesSeparator + " " + v.Y.ToString(culture) + coordinatesSeparator + " " + v.Z.ToString(culture) + ")";
					}

					return base.ConvertTo(context, culture, value, destType);
				}   
			}

            /// <summary>
            /// The Vector3DConverter class allows you to edit vectors in the propties window.
            /// </summary>
            internal class Vector3DConverter : ExpandableObjectConverter
            {
                private const char coordinatesSeparator = ';';

                public override bool CanConvertFrom(ITypeDescriptorContext context, Type t)
                {
                    //	We allow conversion from a string.
                    if (t == typeof(string))
                        return true;

                    return base.CanConvertFrom(context, t);
                }

                public override object ConvertFrom(ITypeDescriptorContext context,
                    CultureInfo culture, object value)
                {
                    //	If it's a string, we'll parse it for coords.
                    if (value is string)
                    {
                        try
                        {
                            string s = (string)value;

                            //	Parse the format (x, y, z).
                            int openbracket = s.IndexOf('(');
                            int firstseparator = s.IndexOf(coordinatesSeparator);
                            int secondseparator = s.IndexOf(coordinatesSeparator, firstseparator + 1);
                            int closebracket = s.IndexOf(')');

                            float xValue, yValue, zValue;

                            if (firstseparator != -1 && openbracket != -1)
                            {
                                //	We have the separator and open bracket, so get x.
                                string parsed = s.Substring(openbracket + 1, (firstseparator - (openbracket + 1)));
                                parsed.Trim();
                                xValue = float.Parse(parsed, culture);

                                if (firstseparator != -1 && secondseparator != -1)
                                {
                                    parsed = s.Substring(firstseparator + 1, (secondseparator - (firstseparator + 1)));
                                    parsed.Trim();
                                    yValue = float.Parse(parsed, culture);

                                    if (secondseparator != -1 && closebracket != -1)
                                    {
                                        parsed = s.Substring(secondseparator + 1, (closebracket - (secondseparator + 1)));
                                        parsed.Trim();
                                        zValue = float.Parse(parsed, culture);

                                        return new Vector3D(xValue, yValue, zValue);
                                    }
                                }
                            }
                        }
                        catch
                        {
                        }
                        //	Somehow we couldn't parse it.
                        throw new ArgumentException("Can not convert '" + (string)value +
                                                    "' to type Vector3D.");
                    }

                    return base.ConvertFrom(context, culture, value);
                }

                public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture,
                    object value, Type destType)
                {
                    if (destType == typeof(string) && value is Point3D)
                    {
                        //	We can easily convert a point to a string, format (x, y, z).
                        Vector3D v = (Vector3D)value;

                        return "(" + v.X.ToString(culture) + coordinatesSeparator + " " + v.Y.ToString(culture) + coordinatesSeparator + " " + v.Z.ToString(culture) + ")";
                    }

                    return base.ConvertTo(context, culture, value, destType);
                }
            }

            /// <summary>
            /// The Vector3DConverter class allows you to edit vectors in the propties window.
            /// </summary>
            internal class GLColorConverter : ExpandableObjectConverter
            {
                private const char coordinatesSeparator = ';';

                public override bool CanConvertFrom(ITypeDescriptorContext context, Type t)
                {
                    //	We allow conversion from a string.
                    if (t == typeof(string))
                        return true;

                    return base.CanConvertFrom(context, t);
                }

                public override object ConvertFrom(ITypeDescriptorContext context,
                    CultureInfo culture, object value)
                {
                    //	If it's a string, we'll parse it for coords.
                    if (value is string)
                    {
                        try
                        {
                            string s = (string)value;

                            //	Parse the format (r, g, b, a).
                            int openbracket = s.IndexOf('(');
                            int firstseparator = s.IndexOf(coordinatesSeparator);
                            int secondseparator = s.IndexOf(coordinatesSeparator, firstseparator + 1);
                            int thirdseparator = s.IndexOf(coordinatesSeparator, secondseparator + 1);
                            int closebracket = s.IndexOf(')');

                            float rValue, gValue, bValue, aValue;

                            if (firstseparator != -1 && openbracket != -1)
                            {
                                //	We have the separator and open bracket, so get x.
                                string parsed = s.Substring(openbracket + 1, (firstseparator - (openbracket + 1)));
                                parsed.Trim();
                                rValue = float.Parse(parsed, culture);

                                if (firstseparator != -1 && secondseparator != -1)
                                {
                                    parsed = s.Substring(firstseparator + 1, (secondseparator - (firstseparator + 1)));
                                    parsed.Trim();
                                    gValue = float.Parse(parsed, culture);

                                    if (secondseparator != -1 && (thirdseparator != -1 || closebracket != -1))
                                    {
                                        if (thirdseparator != -1)
                                            parsed = s.Substring(secondseparator + 1, (thirdseparator - (secondseparator + 1)));
                                        else
                                            parsed = s.Substring(secondseparator + 1, (closebracket - (secondseparator + 1)));
                                        parsed.Trim();
                                        bValue = float.Parse(parsed, culture);

                                        if (thirdseparator != -1 && closebracket != -1)
                                        {
                                            parsed = s.Substring(thirdseparator + 1, (closebracket - (thirdseparator + 1)));
                                            parsed.Trim();
                                            aValue = float.Parse(parsed, culture);
                                        }
                                        else
                                            aValue = 1.0f;

                                        return new GLColor(rValue, gValue, bValue, aValue);
                                    }
                                }
                            }
                        }
                        catch
                        {
                        }
                        //	Somehow we couldn't parse it.
                        throw new ArgumentException("Can not convert '" + (string)value +
                                                    "' to type GLColor.");
                    }

                    return base.ConvertFrom(context, culture, value);
                }

                public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture,
                    object value, Type destType)
                {
                    if (destType == typeof(string) && value is GLColor)
                    {
                        //	We can easily convert a point to a string, format (x, y, z).
                        GLColor v = (GLColor)value;

                        return "(" + v.R.ToString(culture) + coordinatesSeparator + " " + v.R.ToString(culture) + coordinatesSeparator + " " + v.B.ToString(culture) + coordinatesSeparator + " " + v.A.ToString(culture) + ")";
                    }

                    return base.ConvertTo(context, culture, value, destType);
                }
            }
		}		
 	}
}